package com.elbis.business.controller;

import java.io.Serializable;
import java.sql.Date;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;

import javax.faces.event.ValueChangeEvent;

import org.apache.log4j.Logger;

import com.elbis.action.input.ErrorMessages;
import com.elbis.action.input.ErrorsHashMap;
import com.elbis.action.output.InformativeMessages;
import com.elbis.action.output.Pages;
import com.elbis.business.controller.msg.FormFields;
import com.elbis.business.entity.Gamer;
import com.elbis.business.entity.PendingActivation;
import com.elbis.business.entity.locale.City;
import com.elbis.business.entity.locale.Country;
import com.elbis.business.entity.locale.Language;
import com.elbis.business.manager.ActivationManager;
import com.elbis.business.manager.ManageGamer;
import com.elbis.business.manager.MessageManager;
import com.elbis.business.util.ErrorMessageUtil;
import com.elbis.email.generator.ExpiryDateGenerator;
import com.elbis.email.generator.TokenGenerator;

public class RegistrationController implements Serializable {

	private static final long serialVersionUID = -2005044894783204546L;

	private String email;

	private String emailRepeat;

	private String password;

	private String passwordRepeat;

	private String name;

	private String surname;

	private String nationality;

	private String day;

	private String month;

	private String year;

	private Country country;

	private City city;

	private Language language;

	private static final Logger logger = Logger
			.getLogger(RegistrationController.class);

	public String createValidUser() {

		ManageGamer mg = new ManageGamer();

		Gamer existingGamer = mg.getUniqueUser(email);
		if (existingGamer != null) {
			ErrorMessageUtil.addErrorMessage(
					FormFields.EMAIL,
					MessageManager.getErrorMessage(
							ErrorMessages.EMAIL_ADDRESS_ALREADY_DEFINED)
							.getMessage());
			if (logger.isInfoEnabled()) {
				logger.info(ErrorsHashMap
						.getMessage(ErrorMessages.EMAIL_ADDRESS_ALREADY_DEFINED));
			}
			return Pages.REGISTRATION;
		}

		if (!email.equals(emailRepeat)) {
			ErrorMessageUtil.addErrorMessage(FormFields.EMAIL, MessageManager
					.getErrorMessage(ErrorMessages.ENTERED_EMAILS_DO_NOT_MATCH)
					.getMessage());
			if (logger.isInfoEnabled()) {
				logger.info(email
						+ " : "
						+ ErrorsHashMap
								.getMessage(ErrorMessages.ENTERED_EMAILS_DO_NOT_MATCH));
			}
			return Pages.REGISTRATION;
		}

		if (!equalChars(password.toCharArray(), passwordRepeat.toCharArray())) {
			ErrorMessageUtil.addErrorMessage(
					FormFields.PASSWORD_REPEAT,
					MessageManager.getErrorMessage(
							ErrorMessages.ENTERED_PASSWORDS_DO_NOT_MATCH)
							.getMessage());
			if (logger.isInfoEnabled()) {
				logger.info(email
						+ " : "
						+ ErrorsHashMap
								.getMessage(ErrorMessages.ENTERED_PASSWORDS_DO_NOT_MATCH));
			}
			return Pages.REGISTRATION;
		}

		Date dateOfBirth = null;
		if (day != null && month != null && year != null) {
			try {
				int dayint = Integer.valueOf(day);
				int monthint = Integer.valueOf(month);
				int yearint = Integer.valueOf(year);
				GregorianCalendar calendar = new GregorianCalendar();
				calendar.set(yearint, monthint - 1, dayint);
				dateOfBirth = new Date(calendar.getTimeInMillis());
			} catch (NumberFormatException nfe) {
				if (logger.isInfoEnabled()) {
					logger.info("Day, month or year value is non-numeric. ["
							+ day + ", " + month + ", " + year + "]");
				}
			}
		}

		Gamer newGamer = mg.addGamer(email, password, name, surname, language,
				nationality, country, city, dateOfBirth);

		if (newGamer == null) {
			ErrorMessageUtil.addErrorMessage(MessageManager.getErrorMessage(
					ErrorMessages.SYSTEM_ERROR).getMessage());
			logger.error(ErrorsHashMap
					.getMessage(ErrorMessages.PERSISTENCE_MAPPING_ERROR));
			return Pages.REGISTRATION;
		}

		// TODO send activation email
		ActivationManager am = new ActivationManager();
		PendingActivation pending = new PendingActivation();
		pending.setToken(TokenGenerator.generateToken());
		pending.setExpires(ExpiryDateGenerator.generateExpiryDate());
		pending.setGamer(newGamer);
		Long activationId = am.save(pending);
		if (activationId == null) {
			// TODO handle problem with activation link
			ErrorMessageUtil.addErrorMessage(MessageManager.getErrorMessage(
					ErrorMessages.SYSTEM_ERROR).getMessage());
			logger.error(ErrorsHashMap
					.getMessage(ErrorMessages.PERSISTENCE_MAPPING_ERROR));
			return Pages.REGISTRATION;
		}

		// if there is nothing wrong up till here, we have a successful account
		// creation
		ErrorMessageUtil.addInformativeMessage(MessageManager
				.getInformativeMessage(InformativeMessages.ACCOUNT_CREATED)
				.getMessage());
		if (logger.isInfoEnabled()) {
			logger.info("New account created");
		}
		return Pages.IDENTIFIED;
	}

	private boolean equalChars(char[] chars, char[] otherChars) {
		if (chars.length != otherChars.length) {
			return false;
		}
		for (int i = 0; i < chars.length; i++) {
			if (chars[i] != otherChars[i]) {
				return false;
			}
		}
		return true;
	}

	public List<City> getCities() {
		List<City> cities = null;
		if (country != null) {
			cities = country.getCities();
		}
		return cities;
	}

	public void countryChanged(ValueChangeEvent e) {
		Country newCountry = (Country) e.getNewValue();
		country = newCountry;
	}

	public List<String> getDays() {
		List<String> days = new ArrayList<String>();
		for (int i = 1; i <= 31; i++) {
			days.add(String.valueOf(i));
		}
		return days;
	}

	public List<String> getMonths() {
		List<String> months = new ArrayList<String>();
		for (int i = 1; i <= 12; i++) {
			months.add(String.valueOf(i));
		}
		return months;
	}

	public List<String> getYears() {
		List<String> years = new ArrayList<String>();
		GregorianCalendar calendar = new GregorianCalendar();
		int currentYear = calendar.get(GregorianCalendar.YEAR);
		for (int i = currentYear; i > currentYear - 50; i--) {
			years.add(String.valueOf(i));
		}
		return years;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getEmailRepeat() {
		return emailRepeat;
	}

	public void setEmailRepeat(String emailRepeat) {
		this.emailRepeat = emailRepeat;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getPasswordRepeat() {
		return passwordRepeat;
	}

	public void setPasswordRepeat(String passwordRepeat) {
		this.passwordRepeat = passwordRepeat;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getSurname() {
		return surname;
	}

	public void setSurname(String surname) {
		this.surname = surname;
	}

	public String getNationality() {
		return nationality;
	}

	public void setNationality(String nationality) {
		this.nationality = nationality;
	}

	public String getDay() {
		return day;
	}

	public void setDay(String day) {
		this.day = day;
	}

	public String getMonth() {
		return month;
	}

	public void setMonth(String month) {
		this.month = month;
	}

	public String getYear() {
		return year;
	}

	public void setYear(String year) {
		this.year = year;
	}

	public Country getCountry() {
		return country;
	}

	public void setCountry(Country country) {
		this.country = country;
	}

	public City getCity() {
		return city;
	}

	public void setCity(City city) {
		this.city = city;
	}

	public Language getLanguage() {
		return language;
	}

	public void setLanguage(Language language) {
		this.language = language;
	}

}
